from datetime import timedelta
from typing import Any

from aiogram import Bot, F, types
from aiogram_dialog import Dialog, DialogManager, Window
from aiogram_dialog.widgets.input import TextInput
from aiogram_dialog.widgets.kbd import Back, Cancel, Next, Start
from aiogram_dialog.widgets.text import Const, Format
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from sqlalchemy.ext.asyncio import AsyncSession

from app.bot.states.states import (
    ChangeCapmonsterTokenState,
    ChangeKopeechkaTokenState,
    ProxiesState,
    RegerSettingsState,
    SettingsState,
)
from app.bot.utils.date_time import get_date_time
from app.bot.utils.logger import log
from app.bot.utils.scheduler import jobs
from app.config import Settings
from app.database.functions.stats import update_stats, update_user_stats
from app.database.functions.user import add_user_proxies, get_user


async def get_user_settings(
    session: AsyncSession, dialog_manager: DialogManager, **kwargs
):
    user_id: int = dialog_manager.event.from_user.id
    user = await get_user(session, user_id)

    return {
        "capmonster_token": user.capmonster_token,
        "kopeechka_token": user.kopeechka_token,
        "proxies": user.proxies,
        "all_set": all([user.capmonster_token, user.proxies]),
    }


async def add_proxies(
    call: types.CallbackQuery, widget: Any, manager: DialogManager, collections: str
):
    session = manager.middleware_data.get("session")
    user_id = call.from_user.id

    try:
        await add_user_proxies(session, user_id, collections)
        await call.answer("Прокси обновлены")
        await manager.done()
    except Exception as e:
        log.exception(e)
        await call.answer("Ошибка при обновлении прокси")


async def change_capmonster_token(
    call: types.CallbackQuery, widget: Any, manager: DialogManager, api_key: str
):
    user_id: int = call.from_user.id
    session = manager.middleware_data.get("session")

    try:
        user = await get_user(session, user_id)
        user.capmonster_token = api_key
        await session.commit()
        await call.answer("Токен изменен")

    except Exception as e:
        await call.answer("Ошибка при изменении токена")
        log.exception(e)
    await manager.done()


async def change_kopeechka_token(
    call: types.CallbackQuery, widget: Any, manager: DialogManager, api_key: str
):
    user_id: int = call.from_user.id
    session = manager.middleware_data.get("session")

    if api_key == "0":
        api_key = None

    try:
        user = await get_user(session, user_id)
        user.kopeechka_token = api_key
        await session.commit()
        await call.answer("Токен изменен")

    except Exception as e:
        await call.answer("Ошибка при изменении токена")
        log.exception(e)
    await manager.done()


async def set_accounts_amount(
    message: types.Message, widget: Any, manager: DialogManager, accounts_amount: str
):
    user_id: int = message.from_user.id
    bot: Bot = manager.middleware_data.get("bot")
    session = manager.middleware_data.get("session")
    scheduler: AsyncIOScheduler = manager.middleware_data.get("scheduler")
    config: Settings = manager.middleware_data.get("config")

    user = await get_user(session, user_id)

    cur_date = get_date_time(get_datetime=True)

    scheduler.add_job(
        jobs.generate_wlo_accs,
        run_date=cur_date + timedelta(seconds=5),
        args=(
            bot,
            config,
            int(accounts_amount),
            user,
        ),
    )

    await update_stats(
        session,
        wlo_accs=int(accounts_amount),
    )
    await update_user_stats(
        session, message.from_user.id, wlo_accs_reged=int(accounts_amount)
    )

    log.info(
        f"Добавлена задача по генерации {accounts_amount} аккаунтов wlo для юзера {user_id}"
    )

    await message.answer(
        "Задача добавлена в работу. Вы получите уведомление, когда она будет выполнена"
    )
    await manager.done()


settings_dialog = Dialog(
    Window(
        Const("Настройки регера\n"),
        Const("Введите токен capmonster и добавьте прокси, чтобы запустить регер\n"),
        Format("<b>API токен capmonster.cloud:</b> {capmonster_token}"),
        Format("<b>API токен kopeechka.store (необязательно):</b> {kopeechka_token}"),
        Start(
            Const("🟢 Запустить регер"),
            id="start_reger_settings",
            state=RegerSettingsState.select_amount_of_accounts,
            when=F["all_set"],
        ),
        Start(
            Const("Заменить токен Сapmonster"),
            id="capmonster_token_btn",
            state=ChangeCapmonsterTokenState.change_capmonster_token,
        ),
        Start(
            Const("Заменить токен Kopeechka"),
            id="kopeechka_token_btn",
            state=ChangeKopeechkaTokenState.change_kopeechka_token,
        ),
        Start(
            Const("Список прокси"),
            id="proxies_list_btn",
            state=ProxiesState.proxies_list,
        ),
        state=SettingsState.display_settings,
        getter=get_user_settings,
    ),
)

change_capmonster_token_dialog = Dialog(
    Window(
        Const("Введите новый токен capmonster"),
        TextInput("capmonstertoken", str, on_success=change_capmonster_token),
        Cancel(Const("⬅️ Назад")),
        state=ChangeCapmonsterTokenState.change_capmonster_token,
    ),
)


change_kopeechka_token_dialog = Dialog(
    Window(
        Const(
            "Введите новый токен kopeechka в формате <b>токен&mail.ru,outlook.com.</b>\n\n"
            "– После & введите почты, которые хотите использовать\n"
            "– Введите только токен, чтобы брать все почты\n\n"
            "Отправьте 0, чтобы использовать временную почту вместо копеечки"
        ),
        TextInput("kopeechkatoken", str, on_success=change_kopeechka_token),
        Cancel(Const("⬅️ Назад")),
        state=ChangeKopeechkaTokenState.change_kopeechka_token,
    ),
)


change_proxies_dialog = Dialog(
    Window(
        Const("Список прокси\n"),
        Format("{proxies}", when=F["proxies"]),
        Next(
            Const("Заменить список прокси"),
        ),
        Cancel(Const("⬅️ Назад")),
        state=ProxiesState.proxies_list,
        getter=get_user_settings,
    ),
    Window(
        Const(
            "Введите новый список прокси в формате <b>http://user:password@host:port</b>\n"
            "Каждый прокси с новой строки"
        ),
        TextInput("collectionlist", str, on_success=add_proxies),
        Back(Const("⬅️ Назад")),
        state=ProxiesState.new_proxies,
    ),
)

reger_settings_dialog = Dialog(
    Window(
        Const("Введите количество аккаунтов для регистрации"),
        TextInput("accountsamount", str, on_success=set_accounts_amount),
        Cancel(Const("⬅️ Назад")),
        state=RegerSettingsState.select_amount_of_accounts,
    )
)
